package com.zkh.myutils.template;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.zkh.myutils.expression.Expression;
import com.zkh.myutils.utils.StringUtils;

/**
 * 模板元素
 */
public class TemplateElement {
	/**
	 * 标签类型
	 */
	static final int TYPE_TAG = 1;
	/**
	 * 表达式类型
	 */
	static final int TYPE_EXP = 2;
	/**
	 * 元素类型（1：模板标签，2：模板表达式）
	 */
	private int elemType;
	/**
	 * 开始位置
	 */
	private int start;
	/**
	 * 结束位置
	 */
	private int end;
	/**
	 * 模板标签
	 */
	private TemplateTag templateTag;
	/**
	 * 模板表达式
	 */
	private TemplateExpression templateExpression;
	/**
	 * 子级元素
	 */
	private List<TemplateElement> childElementList;
	/**
	 * 分支在子级元素中的位置（仅if标签含分支）
	 */
	private LinkedList<Integer> branchIndexList;
	
	/**
	 * 新增子级标签
	 * @param child
	 */
	public void addChild(TemplateElement child) {
		//初始化
		if(childElementList==null) {
			childElementList = new ArrayList<>();
		}
		//新增
		childElementList.add(child);
	}
	
	/**
	 * 获取子级标签
	 * @return
	 */
	public List<TemplateElement> getChildElementList() {
		return childElementList;
	}
	
	/**
	 * 解析condition条件值
	 * @param condition condition条件描述
	 * @param paramMap 参数
	 * @return
	 */
	public boolean getConditionValue(String condition, Map<String, Object> paramMap) {
		//获取条件返回值
		Object v = Expression.newInstance(condition).execute(paramMap);
		//不是布尔值
		if(!(v instanceof Boolean)) {
			throw new TemplateException("if标签condition属性结果值必须为布尔类型");
		}
		//返回值
		return (Boolean) v;
	}
	
	/**
	 * 获取condition条件描述
	 * @param tag
	 * @return
	 */
	public String getCondition(TemplateTag tag) {
		//获取条件
		String condition = tag.getAttr("condition");
		//为空
		if(condition==null) {
			throw new TemplateException(tag.getTagName() + "标签没有condition属性");
		}
		return condition;
	}
	

	
	/**
	 * 获取内容
	 * @param element 当前元素
	 * @param templateContent 模板原始内容
	 * @param paramMap 参数
	 * @return
	 */
	public String getContent(TemplateElement element, String templateContent, Map<String, Object> paramMap) {
		//表达式
		if(elemType == TYPE_EXP) {
			//处理数据
			Object val = templateExpression.getExpression().execute(paramMap);
			//返回
			return val==null ? "" : val.toString();
		}
		//标签
		String tagName = templateTag.getTagName();
		//if标签（子标签含elif和else）
		if("if".equals(tagName)) {
			//获取子级元素
			List<TemplateElement> children = element.getChildElementList();
			//elif和else分支标签
			LinkedList<Integer> branchIndexs = element.branchIndexList;
			//满足条件
			if(getConditionValue(getCondition(templateTag), paramMap)) {
				//有子标签
				if(children.size()>0) {
					//有分支，读取第一个分支
					if(branchIndexs.size()>0) {
						//第一个分支
						int firstIndex = branchIndexs.get(0);
						//内容
						String content = templateContent.substring(0, children.get(firstIndex).getStart());
						//处理内容
						for(int i=firstIndex-1; i>=0; i--) {
							//当前元素
							TemplateElement curr = children.get(i);
							//替换
							content = content.substring(0, curr.getStart()) + curr.getContent(curr, templateContent, paramMap) + content.substring(curr.getEnd()+1);
						}
						//返回
						return content.substring(templateTag.getBeginEnd()+1);
					}
					//没有分支
					String content = templateContent.substring(0, templateTag.getEndStart());
					//处理内容
					for(int i=children.size()-1; i>=0; i--) {
						//当前元素
						TemplateElement curr = children.get(i);
						//替换
						content = content.substring(0, curr.getStart()) + curr.getContent(curr, templateContent, paramMap) + content.substring(curr.getEnd()+1);
					}
					//返回
					return content.substring(templateTag.getBeginEnd()+1);
				}
				//直接返回内容
				return templateContent.substring(templateTag.getBeginEnd()+1, templateTag.getEndStart());
			}//其它分支
			else if(branchIndexs.size()>0){
				//遍历elif
				for(int i=0, len=branchIndexs.size()-1; i<len; i++) {
					//当前分支索引
					int currBranchIndex = branchIndexs.get(i);
					//节点
					TemplateElement elem = children.get(currBranchIndex);
					//满足条件
					if(getConditionValue(getCondition(elem.getTemplateTag()), paramMap)) {
						//下个分支索引
						int nextBranchIndex = branchIndexs.get(i+1);
						//下个分支元素
						TemplateElement nextBranchElem = children.get(nextBranchIndex);
						//截取内容
						String content = templateContent.substring(0, nextBranchElem.getStart());
						//处理内容
						for(int k=nextBranchIndex-1; k>currBranchIndex; k--) {
							//当前元素
							TemplateElement curr = children.get(k);
							//替换
							content = content.substring(0, curr.getStart()) + curr.getContent(curr, templateContent, paramMap) + content.substring(curr.getEnd()+1);
						}
						//返回
						return content.substring(elem.getEnd() + 1);
					}
				}
				//else分支索引
				int elseBranchIndex = branchIndexs.getLast();
				//截取内容
				String content = templateContent.substring(0, templateTag.getEndStart());
				//处理内容
				for(int k=children.size()-1; k>elseBranchIndex; k--) {
					//当前元素
					TemplateElement curr = children.get(k);
					//替换
					content = content.substring(0, curr.getStart()) + curr.getContent(curr, templateContent, paramMap) + content.substring(curr.getEnd()+1);
				}
				return content.substring(children.get(elseBranchIndex).getEnd() + 1);
			}
			//没有分支，直接返回空
			return "";
		}//foreach标签
		else if("foreach".equals(tagName)) {
			//获取变量
			String var = templateTag.getAttr("var");
			//公共属性
			String item = templateTag.getAttr("item", "item");
			String index = templateTag.getAttr("index", "index");
			//内容
			StringBuilder sb = new StringBuilder();
			//获取内容
			String content = templateContent.substring(0, templateTag.getEndStart());
			//存在，说明是遍历集合或数组
			if(!StringUtils.isEmpty(var)) {
				//获取值
				Object val = Expression.newInstance(var).execute(paramMap);
				//Collection
				if(val instanceof Collection) {
					//转换类型
					Collection<?> coll = (Collection<?>) val;
					//长度和索引
					int len = coll.size(), i = 0;
					//遍历
					for(Object v: coll) {
						//解析内容并保存
						sb.append(parseTag(element, content, templateContent, renderCurrParams(paramMap, item, v, index, i, i==0, i==len-1)));
						//移动索引
						i++;
					}
				}else if(val instanceof Map) {
					//转换类型
					Map<?, ?> map = (Map<?, ?>) val;
					//长度
					int len = map.size();
					//索引
					int[] idxs = {0};
					//遍历
					map.forEach((k,v)->{
						//解析内容并保存
						sb.append(parseTag(element, content, templateContent, renderCurrParams(paramMap, item, v, index, idxs[0], idxs[0]==0, idxs[0]==len-1)));
						//移动索引
						idxs[0]++;
					});
				}else if(val!=null && val.getClass().isArray()) {
					//长度
					int len = Array.getLength(val);
					//遍历
					for(int i=0; i<len; i++) {
						//解析内容并保存
						sb.append(parseTag(element, content, templateContent, renderCurrParams(paramMap, item, Array.get(val, i), index, i, i==0, i==len-1)));
					}
				}else {
					throw new TemplateException("foreach标签引入的变量必须是Collection、Map集合或数组且不能为null");
				}
			}//其它：for()
			else {
				//开始、结束
				int start = Integer.parseInt(templateTag.getAttr("start"));
				int end = Integer.parseInt(templateTag.getAttr("end"));
				//递增标识
				boolean increase = start<=end;
				//步长
				String step_str = templateTag.getAttr("step");
				//自动判断步长正负
				int step = (StringUtils.isEmpty(step_str) ? 1 : Math.abs(Integer.parseInt(step_str))) * (increase?1:-1);
				//遍历
				for(int i=start; increase ? i<=end : i>=end; i+=step) {
					//解析内容并保存
					sb.append(parseTag(element, content, templateContent, renderCurrParams(paramMap, item, i, index, i, i==start, i==end)));
				}
			}
			//返回结果
			return sb.toString();
		}
		//其它，返回空
		return "";
	}
	
	/**
	 * 设置当前参数
	 */
	public Map<String, Object> renderCurrParams(Map<String, Object> paramMap, String key, Object value, String indexName, int index, boolean isFirst, boolean isEnd) {
		//保存参数
		paramMap.put(key, value);
		paramMap.put(indexName, index);
		paramMap.put("isFirst", isFirst);
		paramMap.put("isEnd", isEnd);
		//返回
		return paramMap;
	}
	
	/**
	 * 解析内容
	 * @param element 标签类型的元素
	 * @param content foreach内容
	 * @param templateContent 模板原始内容
	 * @param paramMap 参数
	 * @return
	 */
	public String parseTag(TemplateElement element, String content, String templateContent, Map<String, Object> paramMap) {
		//获取子级元素
		List<TemplateElement> children = element.getChildElementList();
		//有子元素，则遍历取值
		for(int i=children.size()-1; i>=0; i--) {
			//当前元素
			TemplateElement curr = children.get(i);
			//替换
			content = content.substring(0, curr.getStart()) + curr.getContent(curr, templateContent, paramMap) + content.substring(curr.getEnd()+1);
		}
		//返回
		return content.substring(element.getTemplateTag().getBeginEnd()+1);
	}

	public int getElemType() {
		return elemType;
	}
	public void setElemType(int elemType) {
		this.elemType = elemType;
	}
	public TemplateTag getTemplateTag() {
		return templateTag;
	}
	public void setTemplateTag(TemplateTag templateTag) {
		this.templateTag = templateTag;
	}
	public TemplateExpression getTemplateExpression() {
		return templateExpression;
	}
	public void setTemplateExpression(TemplateExpression templateExpression) {
		this.templateExpression = templateExpression;
	}
	public int getStart() {
		return start;
	}
	public void setStart(int start) {
		this.start = start;
	}
	public int getEnd() {
		return end;
	}
	public void setEnd(int end) {
		this.end = end;
	}
	List<Integer> getBranchIndexList() {
		return branchIndexList;
	}
	LinkedList<Integer> initBranchIndexList() {
		return this.branchIndexList = new LinkedList<>();
	}

	@Override
	public String toString() {
		return "TemplateElement [elemType=" + (elemType==1?"tag":"expression") + ", start=" + start + ", end=" + end + (elemType==1?(", templateTag=" + templateTag):", expression=" + templateExpression.getExpression()) + "]";
	}

	
}
